package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.WemediaConstants;
import com.heima.common.constants.WmNewsMessageConstants;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.utils.common.ThreadLocalUtil;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.service.WmMaterialService;
import com.heima.wemedia.service.WmNewsAuditService;
import com.heima.wemedia.service.WmNewsMaterialService;
import com.heima.wemedia.service.WmNewsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 自媒体图文内容信息表 服务实现类
 * </p>
 *
 * @author itheima
 */
@Slf4j
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Autowired
    private WmNewsAuditService wmNewsAuditService;

    @Override
    public ResponseResult submit(WmNewsDto dto, Integer isSumit) {
        System.out.println("submit:当前线程:"+Thread.currentThread().getId());
        //第一部分：入参校验，都要校验的
        Integer userId = ThreadLocalUtil.getUserId();
        if(userId==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }

        //第二部分：保存文章到媒体库表
        //1.1 复制dto给wmNews
        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(dto, wmNews);

        //1.2 判断如果是自动布局设置布局方式临时为空
        if(dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)){
            wmNews.setType(null);
        }

        //1.3 处理封面图片，将参数中的图片列表数据转为逗号分割的字符串
        // 如图是多图，把图片链接  ，，，
        List<String> coverImageList = dto.getImages();
        if(coverImageList!=null && coverImageList.size()>0){
            String coverImageStr = StringUtils.join(coverImageList, ",");
            wmNews.setImages(coverImageStr);
        }

        //1.4 创建或更新文章
        ResponseResult responseResult = createOrUpdateWmNews(wmNews, isSumit);
        // responseResult 有错误的时，返回responseResult
        if(responseResult != null){
            return responseResult;
        }

        //准备：抽取内容的图片列表
        List<String> contentImageList = extractContent(wmNews.getContent());

        //第三部分：保存内容图片与文章关系
        if(isSumit.equals(WmNews.Status.SUBMIT.getCode()) && contentImageList.size()>0){
            responseResult = saveRelationForContent(wmNews.getId(), contentImageList);
            if(responseResult!=null){
                return responseResult;
            }
        }

        //第四部分：保存封面图片与文章关系
        if(isSumit.equals(WmNews.Status.SUBMIT.getCode())){
            responseResult = saveRelationForCover(wmNews, dto, contentImageList);
            if(responseResult!=null){
                return responseResult;
            }

            //第五部分：异步调用文章审核的任务
            wmNewsAuditService.auditWmNews(wmNews, contentImageList);
        }

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }




    /**
     * 保存封面图片与文章关系
     * @param wmNews 文章
     * @param dto DTO参数
     * @param contentImageList 内容图片地址列表
     * @return
     */
    private ResponseResult saveRelationForCover(WmNews wmNews,WmNewsDto dto, List<String> contentImageList) {
        List<String> coverImageList = dto.getImages(); //封面图片地址列表

        //如果布局方式是自动布局，则封面图片从内容图片中取用
        if(dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)){
            int size = contentImageList.size(); //内容图片数量
            if(size>=3){ //如果内容图片数量大于等于3，则取3张当做封面图片，设置最终封面布局方式为多图布局
                coverImageList = contentImageList.stream().limit(3).collect(Collectors.toList());
                wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
            } else if(size>=1 && size<3){//如果内容图片数量大于等于1小于3，则取1张当做封面图片，设置最终封面布局方式为单图布局
                coverImageList = contentImageList.stream().limit(1).collect(Collectors.toList());
                wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
            } else {//如果内容无图片，则设置封面最终布局方式为无图布局
                wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
            }

            if(coverImageList!=null && coverImageList.size()>0){
                //将最终取到的封面图片地址列表转为表中需要的逗号分割的字符串
                String coverImageStr = StringUtils.join(coverImageList, ",");
                wmNews.setImages(coverImageStr);
            }

            //将布局方式或封面图片进行更新
            this.updateById(wmNews);
        }


        if(coverImageList!=null && coverImageList.size()>0){
            //保存封面图片与文章的引用关系，指定引用类型为主图引用（封面引用）
            this.saveRelation(wmNews.getId(),coverImageList,WemediaConstants.WM_COVER_REFERENCE);
        }

        return null;
    }

    /**
     * 保存内容图片与文章关系，指定素材与文章的引用类型为内容引用
     * @param wmNewsId  文章ID
     * @param contentImageList 内容图片地址列表
     * @return
     */
    private ResponseResult saveRelationForContent(Integer wmNewsId, List<String> contentImageList) {
        ResponseResult responseResult  = saveRelation(wmNewsId, contentImageList, WemediaConstants.WM_CONTENT_REFERENCE);
        if(responseResult!=null){
            return responseResult;
        }
        return null;
    }

    @Autowired
    private WmMaterialService wmMaterialService;

    /**
     * 公共方法：保存素材与文章的关系
     * @param wmNewsId  文章ID
     * @param imageList 素材地址列表
     * @param type 引用类型（0-内容引用， 1-主图引用）
     * @return
     */
    private ResponseResult saveRelation(Integer wmNewsId, List<String> imageList, Integer type) {
        if(imageList!=null && imageList.size()>0){
            //1.根据素材地址列表当做查询条件，去素材表中查询对应的素材ID列表
            List<WmMaterial> wmMaterialList = wmMaterialService.list(Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, imageList).select(WmMaterial::getId));
            List<Integer> materialIdList = wmMaterialList.stream().map(WmMaterial::getId).collect(Collectors.toList());

            //2.遍历素材ID列表，保存素材与文章的应用关系，指定引用类型
            int num = 0;
            for (Integer materialId : materialIdList) {
                WmNewsMaterial wmNewsMaterial = new WmNewsMaterial();
                wmNewsMaterial.setNewsId(wmNewsId); //文章ID
                wmNewsMaterial.setMaterialId(materialId);//素材ID
                wmNewsMaterial.setType(type);//引用类型
                wmNewsMaterial.setOrd(num);//排序序号
                wmNewsMaterialService.save(wmNewsMaterial);
                num++;
            }

        }
        return null;
    }

    /**
     * 抽取内容的图片列表
     * @param content
     * @return
     */
    private List<String> extractContent(String content) {
        List<String> contentImageList = new ArrayList<>();
        if(StringUtils.isNotBlank(content)){
            List<Map> mapList = JSON.parseArray(content, Map.class);
            if(mapList!=null && mapList.size()>0){
                for (Map<String,String> map : mapList) {
                    String type = map.get("type");
                    if(type.equals("image")){
                        String imageUrl = map.get("value");
                        contentImageList.add(imageUrl);
                    }
                }
            }
        }
        return contentImageList;
    }

    @Autowired
    private WmNewsMaterialService wmNewsMaterialService;

    /**
     * 创建（新建）或更新文章（草稿、更新）
     * @param wmNews
     * @return
     */
    private ResponseResult createOrUpdateWmNews(WmNews wmNews,Integer isSubmit) {
        wmNews.setUserId(ThreadLocalUtil.getUserId()); //登录用户ID
        wmNews.setStatus(isSubmit); // 0-保存草稿  1-提交审核
        wmNews.setEnable(1); //默认状态为已上架
        wmNews.setSubmitedTime(new Date());//提交时间

        //如果ID为空，表示需要创建文章数据
        if(wmNews.getId()==null){
            wmNews.setCreatedTime(new Date());//创建时间
            this.save(wmNews);
        } else { //如果ID不为空，表示需要删除关联关系及修改文章
            //1.删除关联关系
            wmNewsMaterialService.remove(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId, wmNews.getId()));

            //2.判断文章是否存在
            WmNews wmNewsDB = this.getById(wmNews.getId());
            if(wmNewsDB == null){
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "需要更新的文章不存在");
            }

            //3.如果存在就更新文章
            this.updateById(wmNews);
        }
        return null;
    }


    @Override
    public ResponseResult list(WmNewsPageReqDto dto) {
        //1.设置分页参数默认值
        dto.checkParam();

        //2.判断用户是否登录
        Integer userId = ThreadLocalUtil.getUserId();
        if(userId==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }

        //3.封装查询条件
        LambdaQueryWrapper<WmNews> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        //3.1 封装固定查询条件：根据用户ID查询
        lambdaQueryWrapper.eq(WmNews::getUserId, userId);
        //3.2 根据dto参数拼接动态查询条件
        if(dto.getStatus()!=null){
            lambdaQueryWrapper.eq(WmNews::getStatus, dto.getStatus()); //根据状态查询
        }
        if(dto.getBeginPubDate()!=null && dto.getEndPubDate()!=null){
            lambdaQueryWrapper.between(WmNews::getPublishTime, dto.getBeginPubDate(), dto.getEndPubDate()); //根据发布时间范围查询
        }
        if(dto.getChannelId()!=null){
            lambdaQueryWrapper.eq(WmNews::getChannelId, dto.getChannelId());//根据频道ID
        }
        if(StringUtils.isNotBlank(dto.getKeyword())){
            lambdaQueryWrapper.like(WmNews::getTitle,dto.getKeyword()); //根据关键字模糊查询
        }

        //3.3 设置查询结果根据发布时间倒排序
        lambdaQueryWrapper.orderByDesc(WmNews::getPublishTime);

        //4.执行分页查询
        IPage<WmNews> page = new Page<>(dto.getPage(),dto.getSize());
        this.page(page, lambdaQueryWrapper);

        //5.封装分页响应结果
        ResponseResult responseResult = new PageResponseResult(dto.getPage(),dto.getSize(),page.getTotal());
        responseResult.setData(page.getRecords());

        //6.响应数据
        return responseResult;
    }

//    @Autowired
//    private KafkaTemplate kafkaTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        //1.判断用户是否登录
        Integer userId = ThreadLocalUtil.getUserId();
        if(userId==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }

        //2.查询文章判断是否存在
        WmNews wmNews = this.getById(dto.getId());
        if(wmNews==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "文章不存在");
        }

        //3.判断文章是否已发布
        if(!wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode())){
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "未发布不能上下架");
        }

        //4.修改文章的enable值
        WmNews wmNewsDB = new WmNews();
        wmNewsDB.setId(dto.getId());
        wmNewsDB.setEnable(dto.getEnable());
        this.updateById(wmNewsDB);

        //5.生产消息到Kafka
        Map<String,Object> newsMap = new HashMap();
        newsMap.put("articleId",wmNews.getArticleId());//APP端文章ID
        newsMap.put("enable", dto.getEnable());//上下架状态
//        String newsJson = JSON.toJSONString(newsMap);
//        kafkaTemplate.send(WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_TOPIC, newsJson);
        rabbitTemplate.convertAndSend("topic.article","article.upOrDown",newsMap);
        //6.响应结果
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
}

















